package com.zxmr.utility.action;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.zxmr.action.Request;
import com.zxmr.action.Response;
import com.zxmr.action.ResponsePayload;
import com.zxmr.action.ResultCode;
import com.zxmr.domain.account.AccountType;
import com.zxmr.domain.account.User;
import com.zxmr.domain.file.File;
import com.zxmr.domain.file.Folder;
import com.zxmr.domain.file.FolderType;
import com.zxmr.domain.file.ResourceAction;
import com.zxmr.domain.file.ResourceLevel;
import com.zxmr.domain.service.ResourceService;
import com.zxmr.navigate.ExecuteException;
import com.zxmr.navigate.Executor;
import com.zxmr.util.ResourceManager;
import com.zxmr.util.Utils;
import com.zxmr.utility.dto.ResourceListDTO;
import com.zxmr.utility.service.UserActionTraceService;

public class FolderAction extends Executor{

	enum method{
		addFolder,
		// file and folder
		queryList,
		queryInfo,
		// only folder
		queryAllFolder,
		update,
		delete;
	}
	
	@Override
	public void execute(Request request, Response response) {
		
		try
		{
			method m = Enum.valueOf(method.class, this.getElement().getMethod());
			switch(m)
			{
			case addFolder:
				addFolder(request,response);
				break;
			case queryList:
				queryList(request,response);
				break;
			case queryAllFolder:
				queryAllFolder(request,response);
				break;
			case queryInfo:
				queryInfo(request,response);
				break;
			case delete:
				delete(request,response);
				break;
			case update:
				update(request,response);
				break;
			}

		}catch(Exception e)
		{
			ResponsePayload payload = new ResponsePayload();
			if(e instanceof ExecuteException)
			{
				payload.setValue(e.getMessage());
			}else
			{
				e.printStackTrace();
				payload.setValue("internal error");
			}
			response.setPayload(payload);
			response.setResult(ResultCode.COMPONENT_ERROR);
		}
	}
	private void update(Request request,Response response)throws ExecuteException
	{
		
		Folder folder = parseFolder(request);
		
		if(Utils.isStringEmptyWithTrim(folder.getName()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.emptyName"));
		
		ResourceService service = new ResourceService();
		Folder orign = service.queryFolder(folder.getId(), request.getAccount().getCompany());
		
		if(orign == null)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.empty"));
		if(orign.getType() == FolderType.System_Defined)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.updateSys"));
		
		ResourceLevel orignLevel = orign.getLevel();
		
		// 当目录权限扩大时  检查是不是超过福目录
		if(folder.getLevel().getIndex() > orign.getLevel().getIndex())
		{
			if(orign.getParent() != 0)
			{
				Folder parent = service.queryFolder(orign.getParent(), request.getAccount().getCompany());
				if(folder.getLevel().getIndex() > parent.getLevel().getIndex())
					throw new ExecuteException(
							ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.levelTooBig",parent.getLevel().toString(),folder.getLevel().toString()));
			}
		}
		
		orign.setLastUpdateTime(Utils.getCurrentTime());
		orign.setLastUpdateUser(request.getAccount().getName());
		orign.setName(folder.getName());
		orign.setDescription(folder.getDescription());
		orign.setLevel(folder.getLevel());
		
		if(!service.updateFolder(orign,orignLevel))
			this.internalErrorResponse(response);
		else
		{
			UserActionTraceService userTraceService = new UserActionTraceService();
			String action  = ResourceManager.getInstance().getMessage("com.zxmr.utility.updateFolder", String.valueOf(orign.getId()),orign.getName());
			userTraceService.addActionTrace(request.getAccount(), action);
		}

	}
	private void delete(Request request,Response response)throws ExecuteException
	{
		long id = getId(request);
		
		ResourceService service = new ResourceService();
		Folder folder  = service.queryFolder(id, request.getAccount().getCompany());
		if(folder == null)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.empty"));
		if(folder.getType() == FolderType.System_Defined)
			throw new ExecuteException(
					ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.deleteSys"));
		
		if(!service.deleteFolder(folder))
			this.internalErrorResponse(response);
		else
		{
			UserActionTraceService userTraceService = new UserActionTraceService();
			String action  = ResourceManager.getInstance().getMessage("com.zxmr.utility.deleteFolder", String.valueOf(folder.getId()),folder.getName());
			userTraceService.addActionTrace(request.getAccount(), action);
		}
	}
	private void addFolder(Request request,Response response)throws ExecuteException
	{
		Folder folder = parseFolder(request);
		folder.setCompany(request.getAccount().getCompany());
		folder.setCreateTime(Utils.getCurrentTime());
		folder.setOwner(request.getAccount().getName());
		folder.setType(FolderType.Customer_Defined);

		validateAddFolderInput(folder);
		
		ResourceService service = new ResourceService();
		long id = service.addFolder(folder);
		if(id == -1)
		{
			this.internalErrorResponse(response);
		}
		else if(folder.getLevel() == ResourceLevel.Protected)
		{
			// copy parent authorization if exist
			service.copyParentFolderAuth(folder.getParent(), id, request.getAccount().getCompany());
			
			UserActionTraceService userTraceService = new UserActionTraceService();
			String action  = ResourceManager.getInstance().getMessage("com.zxmr.utility.addFolder", String.valueOf(folder.getId()),folder.getName());
			userTraceService.addActionTrace(request.getAccount(), action);
		}
	}
	/**
	 * validate folder information for add action
	 * @param folder
	 * @throws ExecuteException
	 */
	private void validateAddFolderInput(Folder folder)throws ExecuteException
	{
		if(Utils.isStringEmptyWithTrim(folder.getName()))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.emptyName"));
		
		//default as public level
		if(folder.getLevel() == null)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.emptyLevel"));
		
		long parent = folder.getParent();
		
		// when parent == 0 then it is root folder
		if(parent != 0 )
		{
			ResourceService service = new ResourceService();
			Folder par = service.queryFolder(parent, folder.getCompany());
			if(par == null)
				throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.emptyParent"));
			
			// child resource level can not be less than parent
			if(par.getLevel().getIndex() < folder.getLevel().getIndex())
				throw new ExecuteException(
						ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.levelTooBig",par.getLevel().toString(),folder.getLevel().toString()));
		}
	}
	/**
	 * parse folder using JSON
	 * @param request
	 * @return
	 * @throws ExecuteException
	 */
	private Folder parseFolder(Request request)throws ExecuteException
	{
		try
		{
			return JSON.parseObject(request.getRequestParameters().get("parameters"), Folder.class);
		}catch(Exception e)
		{
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		}
	}
	
	/**
	 * query all sub folders based on parent
	 * @param request
	 * @param response
	 * @throws ExecuteException
	 */
	private void queryAllFolder(Request request,Response response)throws ExecuteException
	{
		ResourceService service = new ResourceService();
		
		long folder = 0;
		if(!Utils.isStringEmptyWithTrim(request.getRequestParameters().get("id")))
		{
			try
			{
				folder = Long.valueOf(request.getRequestParameters().get("id"));
			}catch(Exception e)
			{
				throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
			}
		}
		
		if(folder != 0)
			authQueryAllFolder(folder,request.getAccount());
		
		List<Folder> folders = service.queryAllFolder(folder, request.getAccount().getCompany());
		
		List<ResourceListDTO> dto = convertFolderToDTO(folders);
		ResponsePayload payload = new ResponsePayload(JSON.toJSONString(dto));
		response.setPayload(payload);
	}
	/**
	 * authorization based on folder and user
	 * @param folder
	 * @param user
	 * @throws ExecuteException
	 */
	private void authQueryAllFolder(long fid,User user)throws ExecuteException
	{
		ResourceService service = new ResourceService();
		Folder folder = service.queryFolder(fid, user.getCompany());
		if(folder == null)
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.empty"));
		
		if(user.getAccountType() != AccountType.Supervisor)
		{
			if(folder.getLevel() == ResourceLevel.Private)
				throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.noauth"));
			
			//for protected then it need check authorization
			if(folder.getLevel() == ResourceLevel.Protected)
			{
				if(!service.isUserAuthorizedForAction(folder.getId(), user, ResourceAction.view))
					throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.folder.noauth"));
			}
		}

	}
	private void queryList(Request request,Response response)throws ExecuteException
	{

		long folder = getId(request);
		
		if(folder != 0)
			authQueryAllFolder(folder,request.getAccount());
		
		ResourceService service = new ResourceService();
		
		List<File> files = null;
		
		// files under 0 is temp files
		if(folder != 0)
		{
			files = service.queryAllFile(folder, request.getAccount().getCompany());
		}

		List<Folder> folders = service.queryAllFolder(folder, request.getAccount().getCompany());

		List<ResourceListDTO> dto = convertFolderToDTO(folders);
		dto.addAll(convertFileToDTO(files));
		
		ResponsePayload payload = new ResponsePayload(JSON.toJSONString(dto));
		response.setPayload(payload);
	}

	private List<ResourceListDTO> convertFolderToDTO(List<Folder> folders)
	{
		List<ResourceListDTO> dto = new ArrayList<ResourceListDTO>();
		
		if(folders != null)
		{
			for(Folder folder : folders)
			{
				ResourceListDTO d = new ResourceListDTO();
				d.setId(String.valueOf(folder.getId()));
				d.setState("closed");
				d.setText(folder.getName());
				d.setFolder(true);
				d.setLevel(folder.getLevel());
				dto.add(d);
			}
		}
		return dto;
	}
	private List<ResourceListDTO> convertFileToDTO(List<File> files)
	{

		List<ResourceListDTO> dto = new ArrayList<ResourceListDTO>();
		if(files != null)
		{
			for(File file : files)
			{
				ResourceListDTO d = new ResourceListDTO();
				d.setId(String.valueOf(file.getId()));
				d.setState("open");
				d.setText(file.getName());
				d.setFolder(false);
				d.setLevel(file.getLevel());
				d.setIconCls("icon-pic");
				dto.add(d);
			}
		}
	
		return dto;
	}
	private long getId(Request request)throws ExecuteException
	{
		String id = request.getRequestParameters().get("id");
		long folder = 0;
		if(!Utils.isStringEmptyWithTrim(id))
		{
			try
			{
				folder = Long.parseLong(id);
			}catch(Exception e)
			{
				throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
			}	
		}
		return folder;
	}
	
	private void queryInfo(Request request,Response response)throws ExecuteException
	{
		long id = getId(request);
		String type = request.getRequestParameters().get("type");
		if(Utils.isStringEmptyWithTrim(type) || (!type.equals("file") && !type.equals("folder")))
			throw new ExecuteException(ResourceManager.getInstance().getMessage("com.zxmr.utility.invalid.parameter"));
		
		ResourceService service = new ResourceService();
		ResponsePayload payload = new ResponsePayload();
		if(type.equals("folder"))
		{
			payload.setValue(JSON.toJSONString(service.queryFolder(id, request.getAccount().getCompany())));
		}else
		{
			payload.setValue(JSON.toJSONString(service.queryFile(id, request.getAccount().getCompany())));
		}
		
		response.setPayload(payload);
	}
}
